package wili.exp.simple;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.antlr.v4.runtime.tree.ParseTree;

import wili.c.Ca;
import wili.exp.simple.antlr.opExpParser.OpExpContext;

/**
 * 
 * @author weilai
 *
 */
class Node {
	public final int id = ++GenID;
	List<Node> sons;
	public String text = "";
	public String clsNameOrOp;
	ParseTree tree;
	public boolean isOp = false;
	Node dad;

	public String getContent() {
		if (tree != null)
			return tree.getText();
		if (this.text == null || this.text.isEmpty()) {
			if (sons.size() == 1) {
				return sons.get(0).toString();
			}
		}
		return this.text;
	}

	void setSons(List<Node> sons) {
		this.sons = sons;
		for (Node son : sons)
			son.dad = this;
	}

	public String toString() {
		if ("".isEmpty() && this.tree != null)
			return this.tree.getText().trim();
		if (!isOp && text != null)
			return text;
		StringBuilder sb = new StringBuilder();
		String cname = this.clsNameOrOp;
		if (cname.endsWith("Context"))
			cname = cname.substring(0, cname.length() - 7);
		sb.append(cname + "(");
		for (int i = 0; i < sons.size(); i++) {
			Node son = sons.get(i);
			if (i > 0)
				sb.append(", ");
			if (son.text != null) {
				sb.append(son.text);
			} else {
				sb.append(son.clsNameOrOp);
			}
		}
		sb.append(")");
		return sb.toString();
	}

	void addSon(Node son) {
		son.dad = this;
		sons.add(son);
	}

	{
		if (id == 3)
			Ca.pause();
	}

	public Node(List<Node> sons) {
		this.isOp = true;
		this.text = "?";
		this.sons = sons;
		this.clsNameOrOp = null;
	}

	void setSon(int ind, Node son) {
		sons.set(ind, son);
		son.dad = this;
	}

	void replaceBy(Node son) {
		int ind = dad.sons.indexOf(this);
		dad.setSon(ind, son);
	}

	public void standardizeByOpPriority() {
		List<List<String>> opsList = new ArrayList<>();
		opsList.add(Arrays.asList(">,<,>=,<=,==,!=".split(",")));//将从最低优先级开始split
		opsList.add(Arrays.asList("=", "+=", "-=", "*=", "/="));
		opsList.add(Arrays.asList("+"));//可以认为+的优先级低于-
		opsList.add(Arrays.asList("-"));
		opsList.add(Arrays.asList("*"));
		opsList.add(Arrays.asList("/"));
		opsList.add(Arrays.asList("^"));
		opsList.add(Arrays.asList("%"));
		this.standardizeByOpPriority(opsList, 0);
	}

	/**
	 * eg. z+b-c+d-z ~>z+b+d-(c+z)
	 */
	static void gatherJiansToJia(Node nod) {
	}

	/**
	 * eg. x*y/b/z*j ~>xyj/(bz)
	 */
	static void gatherChusToCheng(Node nod) {
	}

	private void standardizeByOpPriority(List<List<String>> opsList, int fromInd) {
		/*
			乘除聚集,使连除变乘： x*y/b/z*j ~>xyj/(bz)
			加减聚集,使连减变加： z+b-c+d-z ~>z+b+d-(c+z)
		 */
		if (sons == null)
			return;
		gatherJiansToJia(this);
		gatherChusToCheng(this);
		for (Node son : this.sons) {
			son.standardizeByOpPriority(opsList, 0);
		}
		if (this.isOp || tree instanceof OpExpContext) {
			this.isOp = true;
			if (sons.size() == 1) {
				this.replaceBy(sons.get(0));//无算符; eg. va, fun(1,2)
				return;
			} else if ("(".equals(sons.get(0).text)) {
				this.replaceBy(sons.get(0));//eg. (va + cd)
				this.standardizeByOpPriority();
				return;
			}
			int from = 0;
			List<Node> newSons = null;
			this.isOp = true;
			for (int k = fromInd; k < opsList.size(); k++) {
				List<String> ops = opsList.get(k);
				for (int i = 1; i < sons.size(); i += 2) {
					Node son = sons.get(i);
					Ca.asert(son.tree instanceof ParseTree, "");
					int ind = ops.indexOf(son.text);
					int inc2 = ++inc;
					if (ind != -1) {//找到算符
						List<Node> lefts = sons.subList(from, i);
						from = i + 1;
						if (newSons == null)
							newSons = new ArrayList<>(sons.size());
						if (lefts.size() == 1) {
							newSons.add(lefts.get(0));
						} else {
							Node newSon = new Node(lefts);
							newSon.standardizeByOpPriority(opsList, k + 1);
							newSons.add(newSon);
						}
						for (int j = i + 2; j < sons.size(); j += 2) {//继续向右查找该算符
							Node sonJ = sons.get(j);
							if (sonJ.text.equals(son.text)) {
								List<Node> rights = sons.subList(from, j);
								from = j + 1;
								if (newSons == null)
									newSons = new ArrayList<>(sons.size());
								if (rights.size() == 1) {
									newSons.add(rights.get(0));
								} else {
									Node newSon = new Node(rights);
									newSon.standardizeByOpPriority(opsList, k + 1);
									newSons.add(newSon);
								}
							}
						}
						if (from + 1 == sons.size()) {
							newSons.add(sons.get(from));
						} else if (from < sons.size()) {
							List<Node> rSons = sons.subList(from, sons.size());
							Node rSon = new Node(rSons);
							rSon.standardizeByOpPriority();
							newSons.add(rSon);
						}
						if (this.id == 8)
							Ca.pause();
						this.setSons(newSons);
						if (this.text == null || this.text.equals("?")) {
							this.clsNameOrOp = this.text = son.text;
						}
						return;
					}
				}
			}
		}
	}

	public Node(ParseTree cont, String... leafClsList) {
		this.tree = cont;
		String st = cont.getText();
		//		if (st.matches("true|false|Y|N")) {
		//			this.text = st;
		//			return;
		//		}
		this.clsNameOrOp = cont.getClass().getSimpleName();
		int ct = cont.getChildCount();
		if (ct == 0) {
			text = cont.getText().trim();
			return;
		} else if (ct == 1) {
			for (String leaf : leafClsList) {
				if (clsNameOrOp.equals(leaf)) {
					text = cont.getText().trim();
					return;
				}
			}
		}
		text = null;
		sons = new ArrayList<>(ct);
		for (int i = 0; i < ct; i++) {
			ParseTree son = cont.getChild(i);
			addSon(new Node(son, leafClsList));
		}
	}

	static int GenID, inc;
}
